package com.webrtc.demo.call

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.webrtc.demo.ConnectionManager
import com.webrtc.demo.ConnectionStateListener
import com.webrtc.demo.MediaConnection
import com.webrtc.demo.R
import kotlinx.android.synthetic.main.activity_call.*
import org.webrtc.*

class CallActivity : AppCompatActivity(), ConnectionStateListener {
    private var mLogcatView: TextView? = null
    private var mStartCallBtn: Button? = null
    private var mEndCallBtn: Button? = null
    //    private lateinit var mRootEglBase: EglBase
    //private var mPeerConnection: PeerConnection? = null
    private var mSurfaceTextureHelper: SurfaceTextureHelper? = null
    private var mLocalSurfaceView: SurfaceViewRenderer? = null
    private var mRemoteSurfaceView: SurfaceViewRenderer? = null
    private lateinit var mVideoTrack: VideoTrack
    private lateinit var mAudioTrack: AudioTrack
    private lateinit var mVideoCapturer: VideoCapturer
    val myName: String by lazy { intent.getStringExtra(MY_NAME) }
    val toName: String by lazy { intent.getStringExtra(TO_NAME) }
    private val isCaller: Boolean by lazy { intent.getBooleanExtra(IS_CALLER, false) }

    private lateinit var mediaConnection: MediaConnection

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_call)
        mLogcatView = findViewById(R.id.LogcatView)
        mStartCallBtn = findViewById(R.id.StartCallButton)
        mEndCallBtn = findViewById(R.id.EndCallButton)
        RTCSignalClient.addOnSignalEventListener(mOnSignalEventListener)

        mLocalSurfaceView = findViewById(R.id.LocalSurfaceView)
        mRemoteSurfaceView = findViewById(R.id.RemoteSurfaceView)
        mLocalSurfaceView!!.init(ConnectionManager.rootEglBase.eglBaseContext, null)
        mLocalSurfaceView!!.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)
        mLocalSurfaceView!!.setMirror(true)
        mLocalSurfaceView!!.setEnableHardwareScaler(false /* enabled */)
        mRemoteSurfaceView!!.init(ConnectionManager.rootEglBase.eglBaseContext, null)
        mRemoteSurfaceView!!.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)
        mRemoteSurfaceView!!.setMirror(true)
        mRemoteSurfaceView!!.setEnableHardwareScaler(true /* enabled */)
        mRemoteSurfaceView!!.setZOrderMediaOverlay(true)

        mediaConnection = ConnectionManager.getMedia(toName)
        mediaConnection.registerConnectionStatusListener(this)
        // NOTE: this _must_ happen while PeerConnectionFactory is alive!
        Logging.enableLogToDebugOutput(Logging.Severity.LS_VERBOSE)
        mVideoCapturer =
            createVideoCapturer() ?: throw RuntimeException("createVideoCapturer = null")
        mSurfaceTextureHelper =
            SurfaceTextureHelper.create(
                "CaptureThread",
                ConnectionManager.rootEglBase.eglBaseContext
            )
        mediaConnection.setSurfaceViewRenderer(mLocalSurfaceView!!, mRemoteSurfaceView!!)
        mVideoCapturer.initialize(
            mSurfaceTextureHelper,
            applicationContext,
            mediaConnection.getCapturerObserver()
        )

    }

    private var init: Boolean = false

    override fun onResume() {
        super.onResume()

        if (!init) {
            init = true
            if (isCaller) {
                // 发起呼叫
                StartCallButton.visibility = View.GONE
                EndCallButton.visibility = View.VISIBLE
                RTCSignalClient.sendNegotiate(toName, Negotiate.CALL, mediaType = MediaType.VIDEO) {
                    logcatOnUI("call send success")
                }
            } else {
                // 确认连线
                RTCSignalClient.sendNegotiate(toName, Negotiate.ACK, mediaType = MediaType.VIDEO) {
                    logcatOnUI("ack send success")
                }
                StartCallButton.visibility = View.GONE
                EndCallButton.visibility = View.VISIBLE
            }
        }

        mVideoCapturer.startCapture(
            VIDEO_RESOLUTION_WIDTH,
            VIDEO_RESOLUTION_HEIGHT,
            VIDEO_FPS
        )
    }

    override fun onPause() {
        super.onPause()
        try {
            mVideoCapturer.stopCapture()
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        doEndCall()
        handler.removeCallbacksAndMessages(null)
        mLocalSurfaceView!!.release()
        mRemoteSurfaceView!!.release()
        mVideoCapturer.dispose()
        mSurfaceTextureHelper!!.dispose()
        PeerConnectionFactory.stopInternalTracingCapture()
        PeerConnectionFactory.shutdownInternalTracer()
        RTCSignalClient.removeOnSignalEventListener(mOnSignalEventListener)
    }

    fun onClickStartCallButton(v: View?) {
        doStartCall()
    }

    fun onClickEndCallButton(v: View?) {
        doEndCall()
        finishDelay()
    }

    private fun updateCallState(idle: Boolean) {
        runOnUiThread(Runnable {
            if (idle) {
                mStartCallBtn!!.visibility = View.VISIBLE
                mEndCallBtn!!.visibility = View.GONE
                mRemoteSurfaceView!!.visibility = View.GONE
            } else {
                mStartCallBtn!!.visibility = View.GONE
                mEndCallBtn!!.visibility = View.VISIBLE
                mRemoteSurfaceView!!.visibility = View.VISIBLE
            }
        })
    }

    private fun doStartCall() {
        logcatOnUI("Start Call, Wait ...")

        mediaConnection.connect()
    }

    private fun doEndCall() {
        logcatOnUI("End Call, Wait ...")
        if (!shut)
            RTCSignalClient.sendNegotiate(toName, Negotiate.SHUT, MediaType.VIDEO) {
                logcatOnUI("已挂断")
            }
        hanup()
//        val message = JSONObject()
//        try {
//            message.put("userId", RTCSignalClient.getInstance().getUserId())
//            message.put("msgType", RTCSignalClient.MESSAGE_TYPE_HANGUP)
//            RTCSignalClient.getInstance().sendMessage(message)
//        } catch (e: JSONException) {
//            e.printStackTrace()
//        }
    }

    private fun hanup() {
        logcatOnUI("Hanup Call, Wait ...")
        mediaConnection.close()
        logcatOnUI("Hanup Done.")
        updateCallState(true)
    }

    /*
     * Read more about Camera2 here
     * https://developer.android.com/reference/android/hardware/camera2/package-summary.html
     **/
    private fun createVideoCapturer(): VideoCapturer? {
        return if (Camera2Enumerator.isSupported(this)) {
            createCameraCapturer(Camera2Enumerator(this))
        } else {
            createCameraCapturer(Camera1Enumerator(true))
        }
    }

    private fun createCameraCapturer(enumerator: CameraEnumerator): VideoCapturer? {
        val deviceNames = enumerator.deviceNames
        // First, try to find front facing camera
        Log.d(TAG, "Looking for front facing cameras.")
        for (deviceName in deviceNames) {
            if (enumerator.isFrontFacing(deviceName)) {
                Logging.d(
                    TAG,
                    "Creating front facing camera capturer."
                )
                val videoCapturer: VideoCapturer? = enumerator.createCapturer(deviceName, null)
                if (videoCapturer != null) {
                    return videoCapturer
                }
            }
        }
        // Front facing camera not found, try something else
        Log.d(TAG, "Looking for other cameras.")
        for (deviceName in deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                Logging.d(TAG, "Creating other camera capturer.")
                val videoCapturer: VideoCapturer? = enumerator.createCapturer(deviceName, null)
                if (videoCapturer != null) {
                    return videoCapturer
                }
            }
        }
        return null
    }

    private var shut: Boolean = false

    private val mOnSignalEventListener: OnSignalEventListener =
        object : OnSignalEventListener {

            override fun onNegotiate(uid: String, type: Negotiate): Boolean {
                if (uid != toName) return false

                if (type == Negotiate.SHUT) {
                    logcatOnUI("对方已挂断")
                    shut = true
                    finishDelay()
                } else if (isCaller) {
                    // 我呼叫
                    when (type) {
                        Negotiate.ACK -> {
                            logcatOnUI("ack received")
                            doStartCall()
                        }
                        Negotiate.DENY -> {
                            logcatOnUI("呼叫被拒绝")
                            finishDelay()
                        }
                    }
                }

                return true
            }

            override fun onOffer(
                uid: String,
                sdp: String,
                mediaType: MediaType,
                roomid: String?
            ): Boolean {
                if (uid != toName) return false

                logcatOnUI("Receive Remote Call ...")

                mediaConnection.onOffer(
                    SessionDescription(
                        SessionDescription.Type.OFFER, sdp
                    )
                )

                return true
            }

            override fun onAnswer(
                uid: String,
                sdp: String,
                mediaType: MediaType,
                roomid: String?
            ): Boolean {
                if (uid != toName) return false

                logcatOnUI("Receive Remote Answer ...")

                mediaConnection.onAnswer(
                    SessionDescription(
                        SessionDescription.Type.ANSWER, sdp
                    )
                )

                updateCallState(false)
                return true
            }

            override fun onCandidate(
                uid: String,
                ice: IceCandidate,
                mediaType: MediaType,
                roomid: String?
            ): Boolean {
                if (uid != toName) return false

                logcatOnUI("Receive Remote Candidate ...")
                mediaConnection.onIceCandidate(ice, true)
                return true
            }

        }

    private val handler = Handler()

    private fun finishDelay() {
        handler.postDelayed({
            finish()
        }, 500)
    }

    private fun logcatOnUI(msg: String) {
        Log.i(TAG, msg)
        runOnUiThread(Runnable {
            val output = mLogcatView!!.text.toString() + "\n" + msg
            mLogcatView!!.text = output
        })
    }

    companion object {
        private const val VIDEO_RESOLUTION_WIDTH = 1280
        private const val VIDEO_RESOLUTION_HEIGHT = 720
        private const val VIDEO_FPS = 30
        private const val TAG = "CallActivity"

        const val MY_NAME = "MY_NAME"
        const val TO_NAME = "TO_NAME"
        const val IS_CALLER = "IS_CALLER"

        fun launch(context: Context, myName: String, toName: String, isCaller: Boolean) {
            context.startActivity(
                Intent(context.applicationContext, CallActivity::class.java).putExtra(
                    MY_NAME, myName
                ).putExtra(TO_NAME, toName)
                    .putExtra(IS_CALLER, isCaller)
            )
        }
    }

    override fun onConnectState(state: PeerConnection.PeerConnectionState) {
        logcatOnUI("连接状态:$state")
    }
}